package com.youaishujuhui.devops.web.controller.game;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.FieldFilter;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Record;
import org.nutz.dao.impl.NutDao;
import org.nutz.dao.impl.SimpleDataSource;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.Daos;
import org.nutz.json.Json;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.youaishujuhui.devops.web.domain.channel.Channel;
import com.youaishujuhui.devops.web.domain.game.Game;
import com.youaishujuhui.devops.web.domain.game.GameProcess;
import com.youaishujuhui.devops.web.domain.host.Host;
import com.youaishujuhui.devops.web.po.AutoInstallPO;
import com.youaishujuhui.devops.web.po.AutoInstallStatusPO;
import com.youaishujuhui.devops.web.po.HostPO;
import com.youaishujuhui.devops.web.po.SSHExecResult;
import com.youaishujuhui.devops.web.po.Select2PO;
import com.youaishujuhui.devops.web.service.DnsService;
import com.youaishujuhui.devops.web.service.JsonService;
import com.youaishujuhui.devops.web.service.PropertiesService;
import com.youaishujuhui.devops.web.service.SSHService;
import com.youaishujuhui.devops.web.service.channel.ChannelService;
import com.youaishujuhui.devops.web.service.game.GameProcessService;
import com.youaishujuhui.devops.web.service.game.GameService;
import com.youaishujuhui.devops.web.service.host.HostService;
import com.youaishujuhui.devops.web.util.syslog.SystemLog;
import com.youaishujuhui.devops.web.vo.Result;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.RuntimeUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

@Controller
@RequestMapping("/game/game_process")
public class GameProcessController {
	
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
    private GameProcessService gameProcessService;
	
	@Autowired
	private GameService gameService;
	
	@Autowired
	private ChannelService channelService;
	
	@Autowired
	private HostService hostService;
	
    @Autowired
    private JsonService jsonService;
    
    @Resource(name = "nutDao")
    private NutDao dao;
    
    @Autowired
    private SSHService sshService;
    
    @Autowired
    private PropertiesService propertiesService;
    
    @Autowired
    private DnsService dnsService;

    @RequestMapping("/page")
    public ModelAndView page() {
        return new ModelAndView("game/game_process");
    }
    
    @RequestMapping("/printList")
    public ModelAndView printList() {
    	List<Channel> channels = channelService.query();
        return new ModelAndView("game/print_list").addObject("channels", channels);
    }
    
    @RequestMapping("/findById")
    @ResponseBody
    public Result<GameProcess> findById(Integer id){
        Result<GameProcess> result = new Result<>();
        GameProcess po = gameProcessService.fetch(id);
        if(po == null){
            result.setCode(Result.FAIL);
            result.setMsg(String.format("记录已不存在！"));
        } else {
        	po = gameProcessService._fetchLinks(po, null);
            result.setCode(Result.SUCCESS);
            result.setData(po);
        }

        return result;
    }
    
    @SystemLog(module = "游戏服管理", oper = "修改游戏服")
    @RequestMapping("/edit")
    @ResponseBody
    public Result<String> edit(GameProcess po){
        Result<String> result = new Result<>();
        
    	if (StringUtils.isEmpty(po.getName())) {
    		po.setName(null);
    	}
        
    	FieldFilter fm = FieldFilter.create(GameProcess.class, "^name$", false);
    	Daos.ext(dao, fm).update(po);
    	
        result.setCode(Result.SUCCESS);
        result.setMsg("修改成功！");
        return result;
    }
    
    @SystemLog(module = "游戏服管理", oper = "删除游戏服")
    @RequestMapping("/del")
    @ResponseBody
    public Result<String> delete(Integer id){
        Result<String> result = new Result<>();
        
        GameProcess gp = new GameProcess();
        
        gp.setGpId(id);
        gp.setState(-1);
        gameProcessService._update(gp, "^state$");
        
        result.setCode(Result.SUCCESS);
        result.setMsg("删除成功！");
        return result;
    }
    
    @SystemLog(module = "游戏服管理", oper = "业务停服")
    @RequestMapping("/close")
    @ResponseBody
    public Result<String> close(String ids){
        Result<String> result = new Result<>();
        
        if (ids != null) {
        	Date now = new Date();
        	for (String id : ids.split(",")) {
        		GameProcess gp = gameProcessService.fetch(Integer.parseInt(id));
        		if (gp != null) {
        			gp.setState(0);
        			gp.setOffTime(now);
        			
        			if (gameProcessService._update(gp, "^state|offTime$") > 0) {
        				gp = gameProcessService._fetchLinks(gp, "host");
        				Host host = gp.getHost();
        				
        				if (host != null) {
        					hostService.updateCurGameServerCount(host, host.getCurGameServerCount() - 1);
        				}
        				
        			}
        		}
        	}
        }
        
        result.setCode(Result.SUCCESS);
        result.setMsg("操作成功！");
        return result;
    }
    
    @RequestMapping("/start")
    @ResponseBody
    public Result<String> start(Integer id){
        Result<String> result = new Result<>();
        
        GameProcess gp = gameProcessService.fetch(id);
        gp = gameProcessService._fetchLinks(gp, "host");
        
        String dir = gp.getDir();
        int processNum = 0;
        
        String cmd = String.format("ps -ef | grep %s | grep -v \"grep\" | wc -l", dir);
        SSHExecResult execResult;
        try {
        	execResult = sshService.exec(gp.getHost().getAvailablePublicIp(), gp.getHost().getSshPort(), cmd);
        	processNum = Integer.parseInt(execResult.getStdout().trim());
        } catch (IOException e) {
			result.setCode(Result.FAIL);
	        result.setMsg(ExceptionUtil.stacktraceToString(e));
	        e.printStackTrace();
	        return result;
		}
        
        if (processNum == 1) {
        	result.setCode(Result.SUCCESS);
            result.setMsg("此游戏服务进程已经启动，请不要重复启动");
            return result;
        } else if (processNum == 0) {
        	cmd = String.format("/data/%s/game_server/bin/gameStart.sh", dir);
        	try {
        		execResult = sshService.exec(gp.getHost().getAvailablePublicIp(), gp.getHost().getSshPort(), cmd);
        	} catch (Exception e) {
        		result.setCode(Result.FAIL);
    	        result.setMsg(ExceptionUtil.stacktraceToString(e));
    	        e.printStackTrace();
    	        return result;
        	}
        }
        
        if (execResult.getExitStatus() == 0 && StringUtils.isEmpty(execResult.getStderr())) {
        	result.setCode(Result.SUCCESS);
        	result.setMsg("成功启动游戏进程");
        } else {
        	result.setCode(Result.FAIL);
        	result.setMsg(execResult.getStderr());
        }

        return result;
    }
    
    @RequestMapping("/auto_add")
    @ResponseBody
    @SystemLog(module = "游戏服管理", oper = "自动部署游戏服")
    public AutoInstallStatusPO autoAdd(int gameId, int channelId, int hostId, String game_server_num, int game_server_id, String domain, String server_name, String game_start_date){
    	
    	AutoInstallStatusPO po = new AutoInstallStatusPO();
    	Map<String, String> msg = new HashMap<String, String>();
    	po.setMsg(msg);
    	
    	// 获取某渠道最后一个装的游戏服
    	List<GameProcess> gameProcesses = gameProcessService.query(Cnd.where("gameId", "=", gameId).
    			and("channelId", "=", channelId).and("state", "=", 1).orderBy("dir", "desc"), 
    			new Pager(1, 1));
    	
    	if (gameProcesses == null || gameProcesses.isEmpty()) {
    		msg.put("error", "此渠道还没有游戏服，请先手动添加游戏服");
    		return po;
    	}
    	
    	Game game = gameService.fetchExistGame(gameId);
    	
    	if (game == null) {
    		msg.put("error", "没有指定的游戏");
    		return po;
    	}
    	
    	Channel channel = channelService.fetch(channelId);
    	
    	if (channel == null) {
    		msg.put("error", "没有指定的渠道");
    		return po;
    	}
        
        GameProcess lastGameProcess = gameProcesses.get(0);
        
        lastGameProcess = gameProcessService._fetchLinks(lastGameProcess, null);
        
        Host host = hostService.fetch(Cnd.where("hostId", "=", hostId).and("state", "=", 1));
        
        if (host == null) {    		
    		msg.put("error", "没有指定的主机");
    		return po;
        }
        
        String toIp = host.getAvailablePublicIp();
        int toSSHPort = host.getSshPort();

        // 传输部署脚本到目标机
        String lastServerIp = lastGameProcess.getHost().getAvailablePublicIp();
        int lastSSHPort = lastGameProcess.getHost().getSshPort();
        String lastServerDir = lastGameProcess.getDir();
        String packageName = game.getPackageDir();
        
        String gameDir = game.getNameEn() + '_' + channel.getNameEn() + '_' + game_server_num;
        
        // 设置返回值
        po.setToIp(toIp);
        po.setToSSHPort(toSSHPort);
        // 写死
        po.setGame_db_slave("192.168.100.1");
        po.setGame_dir(gameDir);
        po.setGame_domain(domain);
        po.setGame_server_id(game_server_id);
        po.setGame_start_date(game_start_date);
        po.setLastServerGameDir(lastServerDir);

    	String fromFile = String.format(propertiesService.getAutoInstallPrefix() + "/game_install_%s.tar.gz", game.getNameEn());
    	String toFile = String.format("/data/game_install_%s.tar.gz", game.getNameEn());
    	try {
    		sshService.SFTPPut(toIp, toSSHPort, fromFile, toFile);
    	} catch (Exception e) {
    		e.printStackTrace();
    		msg.put("transfer_script", "传输部署脚本失败");
    		return po;
    	}
    	
    	// 在目标机上解压部署脚本
    	String cmd = String.format("cd /data;if [ -d game_install_%s ];then rm -rf game_install_%s;fi;tar -mzxvf game_install_%s.tar.gz;", 
    			game.getNameEn(), game.getNameEn(), game.getNameEn());
    	logger.info(toIp + " cmd:" + cmd);
    	try {
    		sshService.exec(toIp, toSSHPort, cmd);
    	} catch (Exception e) {
    		e.printStackTrace();
    		msg.put("uncompress_script", "解压安装包失败");
    		return po;
    	}
    	
    	// 传输部署脚本到尾服
    	fromFile = String.format(propertiesService.getAutoInstallPrefix() + "/game_install_%s.tar.gz", game.getNameEn());
    	toFile = String.format("/data/game_install_%s.tar.gz", game.getNameEn());
    	try {
    		sshService.SFTPPut(lastServerIp, lastSSHPort, fromFile, toFile);
    	} catch (Exception e) {
    		e.printStackTrace();

    		msg.put("transfer_package_create", "传输创建package脚本失败");
    		return po;
    	}
    	
    	// 在尾服上解压部署脚本
    	logger.info(lastServerIp + " cmd:" + cmd);
    	try {
    		sshService.exec(lastServerIp, lastSSHPort, cmd);
    	} catch (Exception e) {
    		e.printStackTrace();

    		msg.put("uncompress_script_create", "解压创建package脚本失败");
    		return po;
    	}
    	
    	// 获取当前游戏渠道记录的版本号
    	// 先写死为未知
    	String gameVersion = "unknow";
    	
    	// 创建最新服务端程序包和数据库结构文件
        cmd = String.format("cd /data/game_install_%s;sh createNewPackage.sh %s %s %s %s %s %s", 
        		game.getNameEn(), game.getNameEn(), lastServerDir, packageName, game.getLogDbName(), game.getGameDbName(), game_server_id);
        logger.info(lastServerIp + " cmd:" + cmd);
        
        try {
    		sshService.exec(lastServerIp, lastSSHPort, cmd);
    	} catch (Exception e) {
    		e.printStackTrace();
    		
    		msg.put("create_package", "创建最新服务端程序包和数据库结构文件失败");
    		return po;
    	}
        
        // 传输生成的package和数据库结构文件
        // 目标部署服和尾服不在一台机时才需要传输
        if (false == toIp.equals(lastServerIp)) {
        	String os = System.getProperty("os.name");  
        	
        	if(os.toLowerCase().startsWith("win")){
        		// 仅仅本地测试
        		// windows，要先安装openssh for windows
        		Process process = null;
        		OutputStream output = null;
        		
				try {
					process = Runtime.getRuntime().exec("cmd");
					output = process.getOutputStream();
					InputStream is = process.getInputStream();
					InputStream errs = process.getErrorStream();
	        		
	        		final String enterStr = "\n";
	        		
	        		output.write(("ssh-agent bash" + enterStr).getBytes());
	        		output.flush();
	        		
	        		if (is.available() > 0) {
	        			byte[] buffer = new byte[is.available()];
	        			is.read(buffer);
	        			
	        			String o = new String(buffer);
	        			System.out.println(o);
	        		}
	        		
	        		if (errs.available() > 0) {
	        			byte[] buffer = new byte[errs.available()];
	        			errs.read(buffer);
	        			
	        			String o = new String(buffer);
	        			System.out.println(o);
	        		}
	        		
	        		output.write(("ssh-add " + propertiesService.getSshKeyPath() + enterStr).getBytes());
	        		output.flush();
	        		
	        		Thread.sleep(1000);
	        		
	        		if (is.available() > 0) {
	        			byte[] buffer = new byte[is.available()];
	        			is.read(buffer);
	        			
	        			String o = new String(buffer);
	        			System.out.println(o);
	        		}
	        		
	        		if (errs.available() > 0) {
	        			byte[] buffer = new byte[errs.available()];
	        			errs.read(buffer);
	        			
	        			String o = new String(buffer);
	        			System.out.println(o);
	        		}
	        		
	        		output.write((propertiesService.getSshKeyPasswd() + enterStr).getBytes());
	        		output.flush();
	        		
	        		Thread.sleep(1000);
	        		
	        		if (is.available() > 0) {
	        			byte[] buffer = new byte[is.available()];
	        			is.read(buffer);
	        			
	        			String o = new String(buffer);
	        			System.out.println(o);
	        		}
	        		
	        		if (errs.available() > 0) {
	        			byte[] buffer = new byte[errs.available()];
	        			errs.read(buffer);
	        			
	        			String o = new String(buffer);
	        			System.out.println(o);
	        		}
	        		
	        		// 耗时操作，要等待
	        		cmd = String.format("ssh -p%s -o StrictHostKeyChecking=no -A -i " + propertiesService.getSshKeyPath() + " root@%s 'scp -P%s -q -r -o StrictHostKeyChecking=no /data/game_install_%s/game_server/%s.tar.gz %s:/data/game_install_%s/game_server'", lastSSHPort, lastServerIp, toSSHPort, game.getNameEn(), packageName, toIp, game.getNameEn());
	        		logger.info("cmd:" + cmd);
	        		
	        		output.write((cmd + enterStr).getBytes());
	        		output.flush();
	        		
	        		Thread.sleep(5000);

	        		cmd = String.format("ssh -p%s -o StrictHostKeyChecking=no -A -i " + propertiesService.getSshKeyPath() + " root@%s 'scp -P%s -q -r -o StrictHostKeyChecking=no /data/game_install_%s/mysql/*.sql %s:/data/game_install_%s/mysql'", lastSSHPort, lastServerIp, toSSHPort, game.getNameEn(), toIp, game.getNameEn());
	        		logger.info("cmd:" + cmd);
	        		
	        		output.write((cmd + enterStr).getBytes());
	        		output.flush();
	        		
	        		Thread.sleep(1000);
				} catch (Exception e) {
					e.printStackTrace();
					
					msg.put("transfer_package", "传输package失败:执行shell脚本失败");
					return po;
				} finally {
					if (output != null) {
						try {
							output.close();
						} catch (IOException e) {
						}
					}
					
					if (process != null) {
						process.destroy();
					}
				}
        	} else {
        		// linux
        		Process process = null;
        		cmd = String.format("ssh -p%s -o StrictHostKeyChecking=no -A -i " + propertiesService.getSshKeyPath() + " root@%s 'scp -P%s -q -r -o StrictHostKeyChecking=no /data/game_install_%s/game_server/%s.tar.gz %s:/data/game_install_%s/game_server'", lastSSHPort, lastServerIp, toSSHPort, game.getNameEn(), packageName, toIp, game.getNameEn());
                try {
                	logger.info("cmd:" + cmd);
                	process = RuntimeUtil.exec("sh", "-c", cmd);
                	int r = process.waitFor();
                	logger.info("result:" + r);
                } catch (Exception e) {
                	e.printStackTrace();
                	
                	msg.put("transfer_package", "传输package失败:执行shell脚本失败");
            		return po;
                } finally {
                	if (process != null) {
                		process.destroy();
                	}
                }
                
                cmd = String.format("ssh -p%s -o StrictHostKeyChecking=no -A -i " + propertiesService.getSshKeyPath() + " root@%s 'scp -P%s -q -r -o StrictHostKeyChecking=no /data/game_install_%s/mysql/*.sql %s:/data/game_install_%s/mysql'", lastSSHPort, lastServerIp, toSSHPort, game.getNameEn(), toIp, game.getNameEn());
                try {
                	logger.info("cmd:" + cmd);
                	process = RuntimeUtil.exec("sh", "-c", cmd);
                	int r = process.waitFor();
                	logger.info("result:" + r);
                } catch (Exception e) {
                	e.printStackTrace();
                	
                	msg.put("transfer_package", "传输数据库结构文件失败");
            		return po;
                } finally {
                	if (process != null) {
                		process.destroy();
                	}
                }
        	}

        }

        // 安装游戏服
        // 没有用到slave，先写死
        final String gameDBSlave = "192.168.100.1";
        cmd = String.format("cd /data/game_install_%s;sh mkdir_and_game_install.sh %s %s %s %s %s %s %s %s %s %s %s > /tmp/%s_install.log 2>/tmp/%s_install_err.log", game.getNameEn(), gameDir, game_server_id, domain, gameDBSlave, game_start_date, game.getLogDbName(), game.getGameDbName(), "1", toIp, gameVersion, server_name, gameDir, gameDir);

        logger.info(toIp + " cmd:" + cmd);
        
        try {
    		sshService.exec(toIp, toSSHPort, cmd);
    	} catch (Exception e) {
    		e.printStackTrace();
    		
    		msg.put("exec_script", "执行装服脚本失败");
    		return po;
    	}
        
        // 把游戏服信息存入数据库表
        int gamePort = game_server_id + 10000;
        int gameGmPort = game_server_id + 20000;
        
        GameProcess newGameProcess = new GameProcess();
        newGameProcess.setChannelId(channelId);
        newGameProcess.setDir(gameDir);
        newGameProcess.setDomain(domain);
        newGameProcess.setGameId(gameId);
        newGameProcess.setGamePort(gamePort);
        newGameProcess.setGmPort(gameGmPort);
        newGameProcess.setHostId(hostId);
        newGameProcess.setName(server_name);
        newGameProcess.setServerId(game_server_id);
        newGameProcess.setState(1);
        
        try {
        	gameProcessService._insert(newGameProcess);
        } catch (Exception e) {
        	e.printStackTrace();
        	msg.put("error", "保存游戏服信息失败");
        	return po;
        }

        // 更新服务器游戏服数量
        try {
        	hostService.updateCurGameServerCount(host, host.getCurGameServerCount() + 1);
        } catch (Exception e) {
        	e.printStackTrace();
        	msg.put("error", "更新服务器游戏服数量失败");
        	return po;
        }
        
        // 解析域名
        StringBuilder dnsResponse = new StringBuilder();
        try {
        	String[] domainTmp = domain.split("\\.");
            String dnsDomain = domainTmp[2] + "." + domainTmp[3];
            String dnsSubDomain = domainTmp[0] + "." + domainTmp[1];
            
            if (false == StringUtils.isEmpty(host.getCtccIp())) {
            	dnsResponse.append(dnsService.createRecord(dnsDomain, dnsSubDomain, "默认", host.getCtccIp()));
            }
            
            if (false == StringUtils.isEmpty(host.getCuccIp())) {
            	dnsResponse.append(dnsService.createRecord(dnsDomain, dnsSubDomain, "联通", host.getCuccIp()));
            }
            
            if (false == StringUtils.isEmpty(host.getCmccIp())) {
            	dnsResponse.append(dnsService.createRecord(dnsDomain, dnsSubDomain, "移动", host.getCmccIp()));
            }
        } catch (Exception e) {
        	e.printStackTrace();
        	msg.put("domainBinding", "域名解析错误：" + e.getMessage() + dnsResponse.toString());
        	return po;
        }
        
        msg.put("domainBinding", dnsResponse.toString());
        
        // 提交游戏服信息给信息后台
        // ro没有提交，先不搞

    	return po;
    }
    
    @RequestMapping("/manual_add")
    @ResponseBody
    @SystemLog(module = "游戏服管理", oper = "手动部署游戏服")
    public Result<String> manualAdd(int gameId, int channelId, int hostId, String game_server_num, int game_server_id, String domain){
        
        Result<String> result = new Result<>();
        
        try {
            GameProcess gp = new GameProcess();
            gp.setGameId(gameId);
            gp.setChannelId(channelId);
            gp.setHostId(hostId);
            gp.setServerId(game_server_id);
            gp.setDomain(domain);
            gp.setGamePort(game_server_id + 10000);
            gp.setGmPort(game_server_id + 20000);
            
            Game game = gameService.fetchExistGame(gameId);
            
            Channel channel = channelService.fetch(channelId);

            gp.setDir(game.getNameEn() + '_' + channel.getNameEn() + '_' + game_server_num);
            gp.setState(1);
            
            gameProcessService._insert(gp);
            hostService.IncrCurGameServerCount(hostId);
            
            result.setMsg("添加成功");
            result.setCode(Result.SUCCESS);
        } catch (Exception e) {
        	result.setMsg(e.getMessage());
        	result.setCode(Result.FAIL);
        }
        
        return result;
    }
    
    @RequestMapping("/query")
    @ResponseBody
    public Result<List<GameProcess>> query(){
        
        Result<List<GameProcess>> result = new Result<>();

        List<GameProcess> list = gameProcessService.queryAll();
        
        result.setData(list);
        result.setCode(Result.SUCCESS);

        return result;
    }
    
    @RequestMapping("/queryHost")
    @ResponseBody
    public String queryHost(String gameId, String channelId) {
    	if (StringUtils.isEmpty(gameId) || StringUtils.isEmpty(channelId)) {
    		return "";
    	}
    	
    	JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();

    	Channel channel = channelService.fetch(Long.parseLong(channelId));
    	List<HostPO> hosts = gameProcessService.queryByGameIdAndChannelId(gameId, channel.getNameEn());
    	JSONArray root = new JSONArray();
    	
    	if (hosts != null) {
    		for (HostPO host : hosts) {
    			JSONObject item = new JSONObject();
    			
    			JSONObject subItem = new JSONObject();
    			subItem.put("game_server_id", host.getServerId());
    			subItem.put("host", host.getHost());
    			subItem.put("port", host.getPort());
    			
    			item.put(host.getDir(), subItem);
    			
    			root.add(item);
    		}
    	}

    	return Json.toJson(root);
    }
    
    /**
     * 自动装游戏服时返回一些数据
     * ajax请求
     * @param gameId
     * @param channelId
     * @return
     */
    @RequestMapping("/getAutoInstallInfo")
    @ResponseBody
    public Result<AutoInstallPO> getAutoInstallInfo(int gameId, int channelId) {
    	Result<AutoInstallPO> result = new Result<AutoInstallPO>();
    	AutoInstallPO po = new AutoInstallPO();

    	// 计算新游戏服的开服序号
    	List<GameProcess> gameProcesses = gameProcessService.query(Cnd.where("gameId", "=", gameId).
    			and("channelId", "=", channelId).orderBy("dir", "desc"), 
    			new Pager(1, 1));
    	
    	if (gameProcesses == null || gameProcesses.isEmpty()) {
    		result.setMsg("此渠道还没有游戏服，请先手动添加游戏服");
    		result.setCode(Result.FAIL);
    		return result;
    	}

    	String dir = gameProcesses.get(0).getDir().split("_")[2];
    	dir = dir.replace("s", "");
    	dir = dir.replace("a", "");
    	
    	String newServerNumTmp = String.valueOf(Integer.parseInt(dir) + 1);
    	String newServerNum;
    	
    	if (newServerNumTmp.length() == 1) {
    		newServerNum = "s00" + newServerNumTmp + "a";
    	} else if (newServerNumTmp.length() == 2) {
    		newServerNum = "s0" + newServerNumTmp + "a";
    	} else {
    		newServerNum = "s" + newServerNumTmp + "a";
    	}
    	
    	// 计算新游戏服的serverId
    	gameProcesses = gameProcessService.query(Cnd.where("gameId", "=", gameId).orderBy("serverId", "desc"));
    	
    	if (gameProcesses == null || gameProcesses.isEmpty()) {
    		result.setMsg("此渠道还没有游戏服，请先手动添加游戏服");
    		result.setCode(Result.FAIL);
    		return result;
    	}
    	
    	int newServerId = gameProcesses.get(0).getServerId() + 1;
    	
    	// 计算域名
    	List<Channel> channels = channelService.query(Cnd.where("channelId", "=", channelId).and("gameId", "=", gameId));
    	
    	if (channels == null || channels.isEmpty()) {
    		result.setMsg("渠道不存在");
    		result.setCode(Result.FAIL);
    		return result;
    	}
    	
    	Game game = gameService.fetchExistGame(gameId);

    	if (game == null) {
    		result.setMsg("游戏不存在");
    		result.setCode(Result.FAIL);
    		return result;
    	}
    	
    	String newDomain = channels.get(0).getNameEn() + newServerNumTmp + game.getNameEn() + '.' + game.getDomain();
    	String property = channels.get(0).getProperty();
    	
    	po.setGame_server_id(newServerId);
    	po.setGame_server_num(newServerNum);
    	po.setGame_domain(newDomain);
    	
    	// 查出可部署机器
    	List<Select2PO> hosts = hostService.queryBestDeployHost(gameId, property);
    	int availableNum = 0;
    	
    	if (hosts == null || hosts.isEmpty()) {
    		result.setMsg("机器不足以部署更多的游戏服，请联系管理员");
    		result.setCode(Result.FAIL);
    		return result;
    	} else {
    		for (Select2PO host : hosts) {
    			availableNum += Integer.parseInt(host.getText().split(":")[1]);
    		}
    	}
    	
    	po.setAvailableNum(availableNum);
    	
    	po.setHosts(hosts);
    	
    	result.setData(po);
    	
    	return result;
    }
    
    @RequestMapping("/game_install_confirm")
    public ModelAndView autoGameInstallConfirm(String po){
    	AutoInstallStatusPO autoInstallStatusPO = Json.fromJson(AutoInstallStatusPO.class, po);
        return new ModelAndView("game/game_install_confirm").addObject("po", autoInstallStatusPO);
    }
    
    @RequestMapping("/game_install_log_status")
    public ModelAndView autoGameInstallLogStatus(String gameDir, String toIp, int toSSHPort){
    	String gameInstallLog, gameInstallErrLog, gameVersion = "";
    	
    	try {
    		// 查看装服的成功信息文件
        	String cmd = String.format("cat /tmp/%s_install.log", gameDir);
        	SSHExecResult result = sshService.exec(toIp, toSSHPort, cmd);
        	gameInstallLog = result.getStdout();
        	
        	// 查看装服的错误信息文件
        	cmd = String.format("cat /tmp/%s_install_err.log", gameDir);
        	result = sshService.exec(toIp, toSSHPort, cmd);
        	gameInstallErrLog = result.getStdout();
        	
        	// 查看游戏服的版本号
        	cmd = String.format("cat /data/%s/game_zw/game_version", gameDir);
        	result = sshService.exec(toIp, toSSHPort, cmd);
        	gameVersion = result.getStdout();
    	} catch (Exception e) {
    		e.printStackTrace();
    		gameInstallLog = "查询日志错误，可能超时";
			gameInstallErrLog = "查询日志错误，可能超时";
    	}

        return new ModelAndView("game/game_install_log_status")
        		.addObject("gameInstallLog", gameInstallLog)
        		.addObject("gameInstallErrLog", gameInstallErrLog)
        		.addObject("gameVersion", gameVersion);
    }
    
    @RequestMapping("/updateGameServerCount")
    @ResponseBody
    public String updateGameServerCount() {
    	List<Host> hosts = hostService.query(Cnd.where("state", "=", 1));
    	if (hosts != null) {
    		for (Host host : hosts) {
    			int curGameServerCount = gameProcessService.count(Cnd.where("hostId", "=", host.getHostId()).and("state", "=", 1));

    			hostService.updateCurGameServerCount(host, curGameServerCount);
    		}
    	}
    	
    	return "ok";
    }

    @RequestMapping("/syncInfoCenterGameServer")
    @ResponseBody
    public String syncInfoCenterGameServer() {
    	JSONObject root = JSON.parseObject(jsonService.getInfoCenterJsonData());
    	
    	List<Game> games = gameService.query(Cnd.where("state", "=", 1));
    	
    	if (games != null) {
    		for (Game game : games) {
    			List<InfoCenterMsg> InfoCenterMsgs = new ArrayList<InfoCenterMsg>();
    			String gameName = game.getNameEn();

    			List<GameProcess> gameProcesses = gameProcessService.query(Cnd.where("gameId", "=", game.getGameId()).and("state", "=", 1));
    		
    			for (Map.Entry<String, Object> entry : root.entrySet()) {
    				if (root.keySet().contains(gameName)) {
    					
    					JSONArray values = (JSONArray) entry.getValue();
    					
    					for (int i = 0; i < values.size(); ++i) {
    						JSONObject dbConfig = values.getJSONObject(i);
    						InfoCenterMsg infoCenterMsg = new InfoCenterMsg(gameName, dbConfig, 
    								new HashMap<Integer, Timestamp>(), new HashMap<Integer, String>(), new HashMap<String, Integer>(), new HashMap<Integer, String>());
    						infoCenterMsg.init();
    						InfoCenterMsgs.add(infoCenterMsg);
    					}
    					
    				}
    			}
    			
    			if (InfoCenterMsgs.isEmpty()) {
    				continue;
    			}
    			
//    			for (InfoCenterMsg infoCenterMsg : InfoCenterMsgs) {
//    				System.out.println(infoCenterMsg);
//    			}
    			
    			for (GameProcess gameProcess : gameProcesses) {
    				Timestamp serverCloseDate = null;
    				String gameServerName = null;
    				String gameAddr = null;
    				int serverId = gameProcess.getServerId();

		            // ##对比每个后台的数据，得到线上真正的游戏服名和合服的日期
    				
    				for (InfoCenterMsg icm : InfoCenterMsgs) {    					
    					if (icm.getNameDict().containsKey(serverId)) {
    						gameServerName = icm.getNameDict().get(serverId);
    					}
    					
    					if (icm.getGameAddrDict().containsKey(serverId)) {
    						gameAddr = icm.getGameAddrDict().get(serverId);
    					}
    					
    					if (icm.getDateDict().containsKey(serverId)) {
    						serverCloseDate = icm.getDateDict().get(serverId);
    					}
    				}
    				
//    				System.out.println(gameServerName);
//    				System.out.println(gameAddr);
//    				System.out.println(serverCloseDate);
    				
    				// 更新数据库游戏服信息
    				if (serverCloseDate != null) {
    					// 表示还没有合服
    					Sql sql = Sqls.create(String.format("UPDATE `t_game_process` SET `offTime`='%s',`name`='%s',`domain`='%s',`state`=0 WHERE gameId=%s AND serverId=%s",
    							serverCloseDate, gameServerName, gameAddr, game.getGameId(), serverId));

    					//System.out.println(sql.toString());
    					
    				    dao.execute(sql);
    				} else {
    					// 母服和线上游戏服更新
    					if (serverId == 1) {
    						continue;
    					}
    					
    					Sql sql = Sqls.create(String.format("UPDATE `t_game_process` SET `offTime`=%s,`name`=%s,`domain`=%s WHERE gameId=%s AND serverId=%s", 
    							"NULL", gameServerName == null ? "NULL": "'" + gameServerName + "'", 
    									gameAddr == null ? "NULL": "'" + gameAddr + "'", game.getGameId(), serverId));
    				
    					//System.out.println(sql.toString());
    					
    				    dao.execute(sql);
    				}
    			}
    		}
    	}

    	return "ok";
    }
    
    @Data
    @AllArgsConstructor
    @ToString
    class InfoCenterMsg {
    	private String gameName;
    	private JSONObject dbConfig;
    	
        private Map<Integer, Timestamp> dateDict;
        private Map<Integer, String> nameDict;
        private Map<String, Integer> jsonDataDict;
        private Map<Integer, String> gameAddrDict;

    	public void init() {
			String host = dbConfig.getString("host");
			int port = dbConfig.getInteger("port");
			String passwd = dbConfig.getString("passwd");
			String userName = dbConfig.getString("user");
			String dbName = dbConfig.getString("db");
    		
    		SimpleDataSource dataSource = new SimpleDataSource();
    		dataSource.setJdbcUrl(String.format("jdbc:mysql://%s:%d/%s?useSSL=false&characterEncoding=UTF-8", host, port, dbName));
    		dataSource.setUsername(userName);
    		dataSource.setPassword(passwd);

    		Dao dao = new NutDao(dataSource);
    		
    		List<Record> records = dao.query("server", null);
    		
    		for (Record record : records) {
    			int id = record.getInt("id");
    			String name = record.getString("name");
    			Timestamp serverCloseDate = record.getTimestamp("mergeTime");
    			int jsonData = record.getInt("pid");
    			String gameAddr = record.getString("host");
    			
                dateDict.put(id, serverCloseDate);
                nameDict.put(id, name);
                jsonDataDict.put(name, jsonData);
                gameAddrDict.put(id, gameAddr);
    		}

    	}
    }
    
    @RequestMapping("/getPrintList")
    @ResponseBody
    public Result<String> getPrintList(String gameId, String[] channelIds) {
    	Result<String> result = new Result<String>();
    	StringBuffer sb = new StringBuffer();
    	
    	if (channelIds != null) {
    		for (String channelId : channelIds) {
    			Channel channel = channelService.fetch(Long.parseLong(channelId));
    			List<HostPO> hosts = gameProcessService.queryByGameIdAndChannelId(gameId, channel.getNameEn());
    			if (hosts != null) {
    				for (HostPO po : hosts) {
    					sb.append(po.getDir() + " " + po.getServerId() + " " + po.getHost() + " " + po.getPort() + "<br>");
    				}
    			}
    		}
    	}

    	result.setCode(Result.SUCCESS);
    	if (StringUtils.isEmpty(sb.toString())) {
    		result.setData("没有数据");
    	} else {
    		result.setData(sb.toString().substring(0, sb.toString().length() - 4));
    	}
    	
    	return result;
    }
    
    public static void main(String[] args) throws IOException, InterruptedException {
    	
    	
		String cmd = "ssh -p22 -o StrictHostKeyChecking=no -A -i F:\\id_rsa_neiwang root@192.168.10.236 'scp -P1022 -q -r -o StrictHostKeyChecking=no /data/game_install_ro/game_server/game_server.tar.gz 192.168.10.226:/data/game_install_ro/game_server'";
		//String cmd = "dir";
    	
    	// System.out.println(RuntimeUtil.execForStr(""));
		Process process = Runtime.getRuntime().exec("cmd");
		InputStream is = process.getInputStream();
		OutputStream os = process.getOutputStream();
		InputStream errs = process.getErrorStream();
		
		Thread.sleep(1000);
		
		if (is.available() > 0) {
			byte[] buffer = new byte[is.available()];
			is.read(buffer);
			
			String output = new String(buffer);
			System.out.println(output);
		}
		
		String enterStr = "\n";
		
		os.write(("ssh-agent bash" + enterStr).getBytes());
		os.flush();
		
		Thread.sleep(1000);
		
		if (is.available() > 0) {
			byte[] buffer = new byte[is.available()];
			is.read(buffer);
			
			String output = new String(buffer);
			System.out.println(output);
		}
		
		os.write(("ssh-add F:\\id_rsa_neiwang\n").getBytes());
		os.flush();
		
		Thread.sleep(1000);
		
		if (is.available() > 0) {
			byte[] buffer = new byte[is.available()];
			is.read(buffer);
			
			String output = new String(buffer);
			System.out.println(output);
		}
		
		if (errs.available() > 0) {
			byte[] buffer = new byte[errs.available()];
			errs.read(buffer);
			
			String output = new String(buffer);
			System.out.println(output);
		}
		
		os.write(("fengniao" + enterStr).getBytes());
		os.flush();
		
		Thread.sleep(1000);
		
		if (is.available() > 0) {
			byte[] buffer = new byte[is.available()];
			is.read(buffer);
			
			String output = new String(buffer);
			System.out.println(output);
		}
		
		if (errs.available() > 0) {
			byte[] buffer = new byte[errs.available()];
			errs.read(buffer);
			
			String output = new String(buffer);
			System.out.println(output);
		}
		
		
		os.write((cmd + enterStr).getBytes());
		os.flush();
		
		Thread.sleep(1000);
		
		if (is.available() > 0) {
			byte[] buffer = new byte[is.available()];
			is.read(buffer);
			
			String output = new String(buffer);
			System.out.println(output);
		}
		
		if (errs.available() > 0) {
			byte[] buffer = new byte[errs.available()];
			errs.read(buffer);
			
			String output = new String(buffer);
			System.out.println(output);
		}

    }
}
